using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Navigation;
using Lib.Approval;
using Lib.Helper;
using MSIACCSL2.ApplicationStateServices;
using MSIACCSL2.BTBServices;
using MSIACCSL2.Command;
using MSIACCSL2.CurrencyServices;
using MSIACCSL2.InventoryServices;
using MSIACCSL2.PurchaseInvoiceServices;
using MSIACCSL2.SupplierServices;
using MSIACCSL2.Views.PurchaseInvoice;
using WcfService1.DTO;
using DeleteDetailCompletedEventArgs = MSIACCSL2.PurchaseInvoiceServices.DeleteDetailCompletedEventArgs;
using GetListByCriteriaCompletedEventArgs = MSIACCSL2.PurchaseInvoiceServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = MSIACCSL2.PurchaseInvoiceServices.GetListCompletedEventArgs;
using SaveCompletedEventArgs = MSIACCSL2.PurchaseInvoiceServices.SaveCompletedEventArgs;

namespace MSIACCSL2.ViewModels
{
    public class PurchaseInvoiceViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static Search frmSearch;
        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        public static Completed OnSearchCompleted;
        private static NavigationService _NavigationService;
        private readonly AplicationStateServicesClient ApplicationService;


        private readonly BTBServicesClient BtbClient;
        private readonly CurrencyServicesClient CurrencyClient;
        private readonly SupplierServicesClient SupplierClient;
        private readonly ValidationHandler validationHandler;
        private int CurrentPage;
        private bool IsUsed;
        private ObservableCollection<int> Pages;
        private ObservableCollection<BTBDTO> _Btbs;
        private ObservableCollection<CurrencyDTO> _Currencys;
        private BTBDTO _CurrentBTB;
        private bool _IsBusy;
        private bool _IsEnabled;
        private PurchaseInvoiceDTO _PurchaseInvoice;
        private PagedCollectionView _PurchaseInvoices;
        private Visibility _SupplierVisibility;
        private ObservableCollection<SupplierDTO> _Suppliers;
        private decimal _TotalQtyUnit;
        private List<string> _errors;
        private Visibility _messageVisibility;
        private PagedCollectionView _pageSources;
        private PurchaseInvoiceServicesClient client;
        private Dictionary<string, object> criteria;
        private string expression;

        public PurchaseInvoiceViewModel()
        {
            _SupplierVisibility = Visibility.Collapsed;
            IsEnabled = true;
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new PurchaseInvoiceServicesClient();
                CurrencyClient = new CurrencyServicesClient();
                SupplierClient = new SupplierServicesClient();
                BtbClient = new BTBServicesClient();
                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SavePurchaseInvoice, CanSave);
                New = new DelegateCommand(NewPurchaseInvoice, CanNew);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchPurchaseInvoice, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                CancelCommand = new DelegateCommand(Cancel, CanCancelCommand);
                LoadBTBCommand = new DelegateCommand(LoadBTB, CanLoadBTBCommand);
                validationHandler = new ValidationHandler();
                MessageVisibility = Visibility.Collapsed;
                ApplicationService = new AplicationStateServicesClient();

                if (mode == Mode.Edit)
                {
                    PrepareEdit();
                    //Mapping BTB for validasi
                }
                else if (mode == Mode.Search)
                {
                    PurchaseInvoice = new PurchaseInvoiceDTO();
                    PurchaseInvoice.PIDate = null;
                    GetBtbList();
                    GetCurrencyList();
                    GetSupplierList();
                }
                else if (mode == Mode.Add)
                {
                    PrepareAdd();
                }
                else
                {
                    GetList(1, null);
                }
            }
        }


        public PagedCollectionView PurchaseInvoices
        {
            get { return _PurchaseInvoices; }

            private set
            {
                if (PurchaseInvoices == value) return;
                _PurchaseInvoices = value;
                int i = (CurrentPage*30);
                foreach (object PurchaseInvoice in PurchaseInvoices)
                {
                    i += 1;

                    ((PurchaseInvoiceDTO) PurchaseInvoice).No = i;
                }
                FirePropertyChanged("PurchaseInvoices");
                PurchaseInvoices.CollectionChanged += PurchaseInvoice_CollectionChanged;
            }
        }

        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }


        public ObservableCollection<BTBDTO> Btbs
        {
            get { return _Btbs; }
            private set
            {
                if (Btbs == value) return;
                _Btbs = value;
                FirePropertyChanged("Btbs");
            }
        }


        public ObservableCollection<CurrencyDTO> Currencys
        {
            get { return _Currencys; }
            private set
            {
                if (Currencys == value) return;
                _Currencys = value;
                FirePropertyChanged("Currencys");
            }
        }


        public Decimal TotalQtyUnit
        {
            get { return _TotalQtyUnit; }
            set
            {
                if (TotalQtyUnit == value) return;
                _TotalQtyUnit = value;
                FirePropertyChanged("TotalQtyUnit");
            }
        }


        public ObservableCollection<SupplierDTO> Suppliers
        {
            get { return _Suppliers; }
            private set
            {
                if (Suppliers == value) return;
                _Suppliers = value;
                FirePropertyChanged("Suppliers");
            }
        }

        public BTBDTO CurrentBTB
        {
            get { return _CurrentBTB; }
            private set
            {
                if (CurrentBTB == value) return;
                _CurrentBTB = value;
                FirePropertyChanged("CurrentBTB");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }

        public Visibility SupplierVisibility
        {
            get { return _SupplierVisibility; }
            internal set
            {
                _SupplierVisibility = value;
                FirePropertyChanged("SupplierVisibility");
            }
        }

        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public PurchaseInvoiceDTO PurchaseInvoice
        {
            get { return _PurchaseInvoice; }
            private set
            {
                if (PurchaseInvoice == value) return;
                _PurchaseInvoice = value;
                FirePropertyChanged("PurchaseInvoice");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }
        public ICommand CancelCommand { get; set; }

        public List<string> Errors
        {
            get { return _errors; }
            private set
            {
                if (Errors == value) return;
                _errors = value;
                FirePropertyChanged("Errors");
            }
        }

        public Visibility MessageVisibility
        {
            get { return _messageVisibility; }
            private set
            {
                if (MessageVisibility == value) return;
                _messageVisibility = value;
                FirePropertyChanged("MessageVisibility");
            }
        }

        public bool IsEnabled
        {
            get { return _IsEnabled; }
            internal set
            {
                _IsEnabled = value;
                FirePropertyChanged("IsEnabled");
            }
        }

        public ICommand LoadBTBCommand { get; set; }

        private void PrepareEdit()
        {
            PurchaseInvoice = (PurchaseInvoiceDTO) Navigation.Args;
            GetPurchaseInvoice(PurchaseInvoice.PINo);
            CekTransaksi();
        }

        private void PrepareAdd()
        {
            //GetLastNoPurchaseInvoice();
            GetBtbList();
            GetCurrencyList();
            GetSupplierList();

            PurchaseInvoice = new PurchaseInvoiceDTO();
            PurchaseInvoice.PurchaseInvoiceDetails = new ObservableCollection<PurchaseInvoiceDetailDTO>();
            var PurchaseInvoiceDetail = new PurchaseInvoiceDetailDTO();
            PurchaseInvoiceDetail.Inventory = new InventoryDTO();
            PurchaseInvoice.Btbs = new ObservableCollection<BTBDTO>();
            PurchaseInvoice.PurchaseInvoiceDetails.Add(PurchaseInvoiceDetail);
            //CekTransaksi();
        }

        private void GetPurchaseInvoice(string PINo)
        {
            IsBusy = true;
            client.GetPurchaseInvoiceCompleted += client_GetPurchaseInvoiceCompleted;
            client.GetPurchaseInvoiceAsync(PINo);
        }

        private void client_GetPurchaseInvoiceCompleted(object sender, GetPurchaseInvoiceCompletedEventArgs e)
        {
            client.GetPurchaseInvoiceCompleted -= client_GetPurchaseInvoiceCompleted;
            PurchaseInvoice = e.Result;
            if (PurchaseInvoice.Status == Status.Void || PurchaseInvoice.Status == Status.Close) IsEnabled = false;
            GetBtbList();
            GetCurrencyList();
            GetSupplierList();
            if (PurchaseInvoice.PurchaseInvoiceDetails == null)
                PurchaseInvoice.PurchaseInvoiceDetails = new ObservableCollection<PurchaseInvoiceDetailDTO>();
            if (PurchaseInvoice.PurchaseInvoiceDetails.Count == 0)
                PurchaseInvoice.PurchaseInvoiceDetails.Add(new PurchaseInvoiceDetailDTO());
            IsBusy = false;
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void PurchaseInvoice_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SavePurchaseInvoice(Object purchaseInvoice)
        {
            //PurchaseInvoice = (PurchaseInvoiceDTO) purchaseInvoice;
            if (PurchaseInvoice.PurchaseInvoiceDetails.Count == 1)
            {
                //Bila tidak ada yang dipilih di detail maka details harus dihapus
                if (PurchaseInvoice.PurchaseInvoiceDetails[0].Inventory == null)
                    PurchaseInvoice.PurchaseInvoiceDetails.Clear();
            }
            Validate();
            if (Errors.Count > 0) return;
            //Hitung Biaya Forwarder untuk tiap 2 SerialNumber 
            HitungBiayaForwarderDetail();
            //HitungBiayaImport();
            PurchaseInvoice.created_by = GlobalVar.User.UserID;
            PurchaseInvoice.modified_by = GlobalVar.User.UserID;
            IsBusy = true;
            client.SaveCompleted += client_SaveCompleted;
            client.SaveAsync(PurchaseInvoice, mode);
        }

        private void client_SaveCompleted(object sender, SaveCompletedEventArgs e)
        {
            if (e.Error != null) Validate(e.Error.ToString());
            client.SaveCompleted -= client_SaveCompleted;
            mode = (Mode) e.UserState;
            if (e.Result)
            {
                IsBusy = false;
                ClearTransaksi(mode);
                mode = Mode.Idle;
                Navigation.MyNavigation.Navigate(new Uri("/PurchaseInvoice/Index", UriKind.Relative));
            }
            else
            {
                IsBusy = false;
                MessageBox.Show("Simpan gagal, periksa data anda!");
            }
        }

        private void HitungBiayaForwarderDetail()
        {
            //decimal LuasSeluruh = PurchaseInvoice.PurchaseInvoiceDetails.Sum(p => p.Inventory.QtyUnit);
            //foreach (PurchaseInvoiceDetailDTO purchaseInvoiceDetail in PurchaseInvoice.PurchaseInvoiceDetails)
            //{
            //    purchaseInvoiceDetail.BiayaForwarder = purchaseInvoiceDetail.Inventory.QtyUnit*
            //                                           PurchaseInvoice.BiayaForwarder/LuasSeluruh;
            //}

            if (CurrentBTB == null) return;
            PurchaseOrderDTO PO = CurrentBTB.PurchaseOrder;


            foreach (PurchaseInvoiceDetailDTO purchaseInvoiceDetail in PurchaseInvoice.PurchaseInvoiceDetails)
            {
                if (purchaseInvoiceDetail.BiayaForwarder != 0) continue;
                decimal TotalDetailSubGroup =
                    PO.PurchaseOrderDetails.Where(
                        x => x.SubGroup.SubGroupID == purchaseInvoiceDetail.Inventory.Item.SubGroup.SubGroupID).Sum(
                            x => (x.TotalDetail));
                decimal TotalPO = PO.Total;
                decimal BiayaForwarderSubgroup = (TotalDetailSubGroup/TotalPO)*PurchaseInvoice.BiayaForwarder;
                purchaseInvoiceDetail.BiayaForwarder = BiayaForwarderSubgroup/
                                                       PurchaseInvoice.PurchaseInvoiceDetails.Count(
                                                           x =>
                                                           x.Inventory.Item.SubGroup.SubGroupID ==
                                                           purchaseInvoiceDetail.Inventory.Item.SubGroup.SubGroupID);
            }
        }

        //private void HitungBiayaImport()
        //{
        //    int TotalSerialNumber = PurchaseInvoice.PurchaseInvoiceDetails.Count;
        //    foreach (PurchaseInvoiceDetailDTO purchaseInvoiceDetail in PurchaseInvoice.PurchaseInvoiceDetails)
        //    {
        //        purchaseInvoiceDetail.BiayaImport = (PurchaseInvoice.BiayaLain + PurchaseInvoice.BiayaTrucking)/
        //                                            TotalSerialNumber;
        //    }
        //}

        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListCompleted += client_GetListCompleted;
            client.GetListAsync(page ?? 1, sortProp, OrderType);
        }

        private void client_GetListCompleted(object sender, GetListCompletedEventArgs e)
        {
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            client.GetListCompleted -= client_GetListCompleted;
            PurchaseInvoices = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }


        private void NewPurchaseInvoice(Object param)
        {
            mode = Mode.Add;
            Navigation.MyNavigation = (NavigationService) param;
            Navigation.MyNavigation.Navigate(new Uri("/PurchaseInvoice/frmAdd", UriKind.Relative));
        }


        private void SearchPurchaseInvoice(Object param)
        {
            mode = Mode.Search;
            frmSearch = new Search();
            frmSearch.Show();
        }


        private void SearchResult(Object param)
        {
            criteria = new Dictionary<string, object>();

            foreach (PropertyInfo prop in PurchaseInvoice.GetType().GetProperties())
            {
                if (prop.Name.Contains("Btbs"))continue;
                if (prop.PropertyType == typeof (Decimal))
                {
                    if ((Decimal) prop.GetValue(PurchaseInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int32))
                {
                    if ((Int32) prop.GetValue(PurchaseInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int64))
                {
                    if ((Int64) prop.GetValue(PurchaseInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Double))
                {
                    if ((Double) prop.GetValue(PurchaseInvoice, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (String))
                {
                    if (String.IsNullOrEmpty((String) prop.GetValue(PurchaseInvoice, null))) continue;
                }
                if (prop.PropertyType == typeof (DateTime))
                {
                    if (prop.GetValue(PurchaseInvoice, null).ToString().Contains("0001")) continue;
                }
                if (prop.GetValue(PurchaseInvoice, null) == null) continue;
                if (prop.PropertyType.Name == "No") continue;

                if (prop.PropertyType.Name.ToLower().Contains("dto"))
                {
                    foreach (PropertyInfo propertyInfo in prop.GetValue(PurchaseInvoice, null).GetType().GetProperties()
                        )
                    {
                        if (propertyInfo.Name.ToLower().Contains("id") || propertyInfo.Name.ToLower().Contains("kode") ||
                            propertyInfo.Name.ToLower().Contains("serial") ||
                            propertyInfo.Name.ToLower().Contains("code"))
                        {
                            criteria.Add(prop.Name, propertyInfo.GetValue(prop.GetValue(PurchaseInvoice, null), null));
                            break;
                        }
                    }
                }
                else
                {
                    criteria.Add(prop.Name, prop.GetValue(PurchaseInvoice, null));
                }
            }

            expression = string.Empty;
            if (frmSearch.rblOr.IsChecked ?? false) expression = "OR";
            else expression = "AND";
            PurchaseInvoiceSearch(criteria, expression,1);
        }

        private void PurchaseInvoiceSearch(Dictionary<String, Object> criteria, string expression,int page)
        {
            if (criteria.ContainsKey("Status")) criteria.Remove("Status");
            frmSearch.DialogResult = true;
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, page);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            client.GetListByCriteriaCompleted -= client_GetListByCriteriaCompleted;
            PurchaseInvoices = new PagedCollectionView(e.Result);
            if (RecordCount != e.recordCount)
            {
                RecordCount = e.recordCount;
                CreatePageNumber();
            }

            IsBusy = false;
        }


        private void GetBtbList()
        {
            BtbClient.GetAllBTBCompleted += BtbClient_GetAllBtbCompleted;
            BtbClient.GetAllBTBAsync();
        }

        private void BtbClient_GetAllBtbCompleted(object sender, GetAllBTBCompletedEventArgs e)
        {
            BtbClient.GetAllBTBCompleted -= BtbClient_GetAllBtbCompleted;
            Btbs = e.Result;
            if (PurchaseInvoice.Btbs != null)
                foreach (var btb in PurchaseInvoice.Btbs)
                {
                    btb.Checked = true;
                    Btbs.Add(btb);
                }
        }

        private void GetCurrencyList()
        {
            CurrencyClient.GetAllCurrencyCompleted += CurrencyClient_GetAllCurrencyCompleted;
            CurrencyClient.GetAllCurrencyAsync();
        }

        private void CurrencyClient_GetAllCurrencyCompleted(object sender, GetAllCurrencyCompletedEventArgs e)
        {
            CurrencyClient.GetAllCurrencyCompleted -= CurrencyClient_GetAllCurrencyCompleted;
            Currencys = e.Result;
            PurchaseInvoice.Currency = Currencys.FirstOrDefault(x => x.CurrencyCode == "Rp");
            PurchaseInvoice.Kurs = 1;

            if (PurchaseInvoice != null)
            {
                if (PurchaseInvoice.Currency == null) return;
                PurchaseInvoice.Currency =
                    Currencys.FirstOrDefault(s => s.CurrencyCode == PurchaseInvoice.Currency.CurrencyCode);
            }
        }

        private void GetSupplierList()
        {
            SupplierClient.GetAllSupplierCompleted += SupplierClient_GetAllSupplierCompleted;
            SupplierClient.GetAllSupplierAsync();
        }

        private void SupplierClient_GetAllSupplierCompleted(object sender, GetAllSupplierCompletedEventArgs e)
        {
            SupplierClient.GetAllSupplierCompleted -= SupplierClient_GetAllSupplierCompleted;
            Suppliers = e.Result;

            if (PurchaseInvoice != null)
            {
                if (PurchaseInvoice.Supplier == null) return;
                PurchaseInvoice.Supplier =
                    Suppliers.FirstOrDefault(s => s.SupplierId == PurchaseInvoice.Supplier.SupplierId);
            }
        }


        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            PurchaseInvoice = null;
            if (PurchaseInvoices != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (mode == Mode.Search)
                    PurchaseInvoiceSearch(criteria, expression, (int)pageIndex + 1);
                else if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }

        public bool CanCancelCommand(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            PurchaseInvoice = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (PurchaseInvoices == null)
                GetList(1, null);
            else
                Complete(this);
        }


        public void Validate(string error = null)
        {
            Errors = new List<string>();
            //if (string.IsNullOrEmpty(PurchaseInvoice.PINo))
            //    Errors.Add("Nomor PI tidak boleh kosong");
            if (null == (PurchaseInvoice.Btbs))
                Errors.Add("BTB harus diisi!");
            if (null == PurchaseInvoice.Supplier)
                Errors.Add("Supplier harus diisi!");
            if (PurchaseInvoice.BiayaForwarder <=0)
                Errors.Add("Biaya Forwarder harus diisi!");
            //validasi Detail PI harus sesuai dengan BTB
            //foreach (PurchaseInvoiceDetailDTO PIDetail in PurchaseInvoice.PurchaseInvoiceDetails)
            //    if (PurchaseInvoice.Btb.BtbDetails.Count(b => b.NoLog == PIDetail.Inventory.SerialNumber) == 0)
            //        Errors.Add("Serial Number " + PIDetail.Inventory.SerialNumber + " tidak sesuai dengan BTB!");

            if (!string.IsNullOrEmpty(error))
                Errors.Add(error);

            if (Errors.Count > 0)
            {
                MessageVisibility = Visibility.Visible;
            }
            else
            {
                MessageVisibility = Visibility.Collapsed;
            }
        }

        public void Cancel(Object param)
        {
            MessageBoxResult res = MessageBox.Show("Are You Sure Want to Cancel ?", "Confirmation",
                                                   MessageBoxButton.OKCancel);
            if (res == MessageBoxResult.OK)
            {
                if (!IsUsed) ClearTransaksi(mode);
                mode = Mode.Idle;
                Navigation.MyNavigation.GoBack();
            }
        }

        private void GetLastNoPurchaseInvoice()
        {
            client = new PurchaseInvoiceServicesClient();
            client.GetLastPINoCompleted += client_GetLastPINoCompleted;
            client.GetLastPINoAsync();
        }

        private void client_GetLastPINoCompleted(object sender, GetLastPINoCompletedEventArgs e)
        {
            client.GetLastPINoCompleted -= client_GetLastPINoCompleted;
            string res = e.Result;
            string formatSO = "0000";
            string kodeSO;
            if (e.Result.Length <= 4)
            {
                res = formatSO;
                kodeSO = e.Result;
            }
            else
            {
                res = e.Result.Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries)[2];
                kodeSO = e.Result.Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries)[0];
            }
            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(res) + 1).ToString().Length) +
                           (int.Parse(res) + 1);

            PurchaseInvoice.PINo = kodeSO + "/" + DateTime.Now.Year + "/" + soNum;
        }

        private void AddPurchaseInvoiceDetail()
        {
            PurchaseInvoice.PurchaseInvoiceDetails.Add(new PurchaseInvoiceDetailDTO());
        }

        public bool CanLoadBTBCommand(Object param)
        {
            return true;
        }

        public void LoadBTB(Object param)
        {
            if (param == null) return;
            BtbClient.GetBTBCompleted += BtbClient_GetBTBCompleted;
            BtbClient.GetBTBAsync(param.ToString());
        }

        private void BtbClient_GetBTBCompleted(object sender, GetBTBCompletedEventArgs e)
        {
            BtbClient.GetBTBCompleted -= BtbClient_GetBTBCompleted;
            if (PurchaseInvoice == null) return;
            PurchaseInvoice.Supplier = e.Result.Supplier;
            PurchaseInvoice.Currency =
                Currencys.FirstOrDefault(x => x.CurrencyCode == e.Result.PurchaseOrder.Currency.CurrencyCode);
            PurchaseInvoice.Term = e.Result.PurchaseOrder.Term;
            PurchaseOrderDTO PO = e.Result.PurchaseOrder;
            if (! PurchaseInvoice.Btbs.Contains(e.Result)) PurchaseInvoice.Btbs.Add(e.Result);
            CurrentBTB = e.Result;
            if (PurchaseInvoice.PurchaseInvoiceDetails.Count == 1)
                if (string.IsNullOrEmpty(PurchaseInvoice.PurchaseInvoiceDetails[0].Inventory.SerialNumber))
                    PurchaseInvoice.PurchaseInvoiceDetails.Clear();

            foreach (BTBDetailDTO btbDetail in e.Result.BtbDetails)
            {
                if (PurchaseInvoice.PurchaseInvoiceDetails.Any(x=>x.Inventory.SerialNumber==btbDetail.NoLog))continue;
                var pid = new PurchaseInvoiceDetailDTO();
                pid.Inventory = new InventoryDTO();
                pid.Inventory.SerialNumber = btbDetail.NoLog;
                pid.Inventory.NoBundle = btbDetail.NoBundle;
                pid.Inventory.QtyPack = btbDetail.QtyPack;
                pid.Inventory.Panjang = btbDetail.Panjang;
                pid.Inventory.Lebar = btbDetail.Lebar;
                pid.Inventory.Tinggi = btbDetail.Tinggi;
                pid.Inventory.QtyUnit = btbDetail.QtyUnit;
                pid.Inventory.Item = btbDetail.Item;

                //Split harga subgroup ke SerialNumber 
                PurchaseOrderDetailDTO PODetail = PO.PurchaseOrderDetails.FirstOrDefault
                    (p => p.SubGroup.SubGroupID == pid.Inventory.Item.SubGroup.SubGroupID);
                Decimal HargaSubgroup = 0;
                if (PODetail != null) HargaSubgroup = PODetail.Price;
                decimal TotalAreaBarang =
                    e.Result.BtbDetails.Where(x => x.Item.SubGroup.SubGroupID == pid.Inventory.Item.SubGroup.SubGroupID)
                        .Sum(x => x.QtyUnit);

                pid.Price = HargaSubgroup*(btbDetail.QtyUnit/TotalAreaBarang);
                GetTotalDetail(pid);
                PurchaseInvoice.PurchaseInvoiceDetails.Add(pid);
            }
        }

        public void UnloadBTB(Object param)
        {
            if (param == null) return;
            BtbClient.GetBTBCompleted += BtbClientUnload_GetBTBCompleted;
            BtbClient.GetBTBAsync(param.ToString());
        }

        private void BtbClientUnload_GetBTBCompleted(object sender, GetBTBCompletedEventArgs e)
        {
            BtbClient.GetBTBCompleted -= BtbClient_GetBTBCompleted;
            if (PurchaseInvoice == null) return;

            for (int i = 0; i < PurchaseInvoice.Btbs.Count; i++)
                if (PurchaseInvoice.Btbs[i].NoBtb == e.Result.NoBtb)
                    PurchaseInvoice.Btbs.RemoveAt(i);

            foreach (BTBDetailDTO btbDetail in e.Result.BtbDetails)
                {
                    var piDetail =
                        PurchaseInvoice.PurchaseInvoiceDetails.FirstOrDefault(
                            x => x.Inventory.SerialNumber == btbDetail.NoLog);
                    if (piDetail != null) PurchaseInvoice.PurchaseInvoiceDetails.Remove(piDetail);
                }
        }

        public void GetTotalDetail(PurchaseInvoiceDetailDTO param)
        {
            PurchaseInvoiceDetailDTO PurchaseInvoiceDetail = param;
            if (PurchaseInvoiceDetail.DiscountType != "%")
                PurchaseInvoiceDetail.TotalDetail = (PurchaseInvoiceDetail.Inventory.QtyUnit*PurchaseInvoiceDetail.Price) -
                                                    PurchaseInvoiceDetail.Discount;
            else
                PurchaseInvoiceDetail.TotalDetail = (PurchaseInvoiceDetail.Inventory.QtyUnit*PurchaseInvoiceDetail.Price) -
                                                    ((PurchaseInvoiceDetail.Price)*PurchaseInvoiceDetail.Discount/100);
            PurchaseInvoice.SubTotal =
                PurchaseInvoice.PurchaseInvoiceDetails.Sum(p => p.TotalDetail);
            if (PurchaseInvoice.DiscountType != "%")
                PurchaseInvoice.AfterDiscount =
                    PurchaseInvoice.SubTotal -
                    PurchaseInvoice.Discount;
            else
                PurchaseInvoice.AfterDiscount =
                    PurchaseInvoice.SubTotal -
                    (PurchaseInvoice.SubTotal*PurchaseInvoice.Discount/
                     100);
            if (PurchaseInvoice.IsPpn)
                PurchaseInvoice.Ppn = PurchaseInvoice.AfterDiscount*10/
                                      100;
            if (PurchaseInvoice.Ppn > 0)
                PurchaseInvoice.IsPpn = true;
            PurchaseInvoice.Total =
                PurchaseInvoice.AfterDiscount + PurchaseInvoice.Ppn;
            TotalQtyUnit =
                PurchaseInvoice.PurchaseInvoiceDetails.Sum(x => x.Inventory.QtyUnit);
        }

        public void GetSupplier(Object param)
        {
            SupplierClient.GetSupplierListCompleted += SupplierClient_GetSupplierListCompleted;
            SupplierClient.GetSupplierListAsync(param.ToString());
        }

        private void SupplierClient_GetSupplierListCompleted(object sender, GetSupplierListCompletedEventArgs e)
        {
            SupplierClient.GetSupplierListCompleted -= SupplierClient_GetSupplierListCompleted;
            Suppliers = e.Result;
            SupplierVisibility = Visibility.Visible;
            EventAggregator.PublishMessage("SupplierSelect", string.Empty);
        }

        public void SupplierSelected(Object param)
        {
            PurchaseInvoice.Supplier = ((SupplierDTO) param);
            SupplierVisibility = Visibility.Collapsed;
        }

        public void Print(Object param)
        {
            Navigation.MyNavigation.Navigate(new Uri("/PurchaseInvoice/PrintPreviewPI", UriKind.Relative));
            Navigation.Args = param;
        }


        public void CekTransaksi()
        {
            ApplicationService.IsTransactionUsedCompleted += ApplicationService_IsTransactionUsedCompleted;
            if (string.IsNullOrEmpty(PurchaseInvoice.PINo))
            {
                ApplicationService.IsTransactionUsedAsync(PurchaseInvoice.ToString(), GlobalVar.User, mode);
                GlobalVar.CurrentTransaction = PurchaseInvoice.ToString();
            }
            else
            {
                ApplicationService.IsTransactionUsedAsync(PurchaseInvoice.PINo, GlobalVar.User, mode);
                GlobalVar.CurrentTransaction = PurchaseInvoice.PINo;
            }
        }

        private void ApplicationService_IsTransactionUsedCompleted(object sender, IsTransactionUsedCompletedEventArgs e)
        {
            ApplicationService.IsTransactionUsedCompleted -= ApplicationService_IsTransactionUsedCompleted;
            IsUsed = e.Result;
            mode = (Mode) e.UserState;
            if (IsUsed)
            {
                MessageBox.Show("Transaksi sedang digunakan!");
                if (mode == Mode.Add) //If Add Mode
                {
                    mode = Mode.Idle;
                    Navigation.MyNavigation.Navigate(new Uri("/PurchaseInvoice/Index", UriKind.Relative));
                }
                else //Edit Mode just view Only
                {
                    IsEnabled = false;
                }
            }
        }

        private void ClearTransaksi(Mode mode)
        {
            ApplicationService.ClearTransactionCompleted += ApplicationService_ClearTransactionCompleted;
            if (mode == Mode.Add)
                ApplicationService.ClearTransactionAsync(PurchaseInvoice.ToString(), GlobalVar.User);
            else
                ApplicationService.ClearTransactionAsync(PurchaseInvoice.PINo, GlobalVar.User);
        }

        private void ApplicationService_ClearTransactionCompleted(object sender, AsyncCompletedEventArgs e)
        {
            ApplicationService.ClearTransactionCompleted -= ApplicationService_ClearTransactionCompleted;
        }

        public void CloseStatus()
        {
            MessageBoxResult res = MessageBox.Show("Are You Sure Want to Close this Transaction ?", "Confirmation",
                                                MessageBoxButton.OKCancel);
            if (res == MessageBoxResult.OK)
            {
                client.UpdateStatusCompleted += new EventHandler<AsyncCompletedEventArgs>(client_UpdateStatusCompleted);
                client.UpdateStatusAsync(PurchaseInvoice, Status.Close);
            }
        }

        void client_UpdateStatusCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.UpdateStatusCompleted -= new EventHandler<AsyncCompletedEventArgs>(client_UpdateStatusCompleted);
            MessageBox.Show("Update Status finished!");
        }
    }


    public class PurchaseInvoiceWrapViewModel : ViewModelBase
    {
        private readonly InventoryServiceClient Inventoryclient;

        private readonly PurchaseInvoiceServicesClient client;
        private List<string> _DiscTypes;

        private ObservableCollection<InventoryDTO> _Inventorys;
        private PurchaseInvoiceDetailDTO _PurchaseInvoiceDetail;

        public PurchaseInvoiceWrapViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                EditCommand = new DelegateCommand(Edit, CanEditCommand);
                DeleteCommand = new DelegateCommand(Delete, CanDeleteCommand);
                client = new PurchaseInvoiceServicesClient();
                Inventoryclient = new InventoryServiceClient();


                AddDetailCommand = new DelegateCommand(AddPurchaseInvoiceDetail, CanAddDetailCommand);
                DeleteDetailCommand = new DelegateCommand(DeletePurchaseInvoiceDetail, CanDeleteDetailCommand);
                GetTotalDetailCommand = new DelegateCommand(GetTotalDetail, CanGetTotalDetailCommand);
                GetPpnCommand = new DelegateCommand(GetPpn, CanGetPpnCommand);
                GetTotalDiscountCommand = new DelegateCommand(GetTotalDiscount, CanGetTotalDiscount);
                GetInventoryCommand = new DelegateCommand(GetInventory, CanGetInventoryCommand);

                DiscTypes = new List<string>();
                DiscTypes.Add("%");
                DiscTypes.Add("val");
                if (PurchaseInvoiceViewModel.mode == Mode.Add || PurchaseInvoiceViewModel.mode == Mode.Edit)
                {
                    // GetInventoryList();
                }
            }
        }

        public PurchaseInvoiceViewModel PurchaseInvoiceViewModel { get; set; }


        public ICommand EditCommand { get; set; }
        public ICommand DeleteCommand { get; set; }
        public ICommand AddDetailCommand { get; set; }
        public ICommand DeleteDetailCommand { get; set; }


        public ObservableCollection<InventoryDTO> Inventorys
        {
            get { return _Inventorys; }
            private set
            {
                if (Inventorys == value) return;
                _Inventorys = value;
                FirePropertyChanged("Inventorys");
            }
        }

        public List<string> DiscTypes
        {
            get { return _DiscTypes; }
            private set
            {
                if (DiscTypes == value) return;
                _DiscTypes = value;
                FirePropertyChanged("DiscTypes");
            }
        }

        public PurchaseInvoiceDetailDTO PurchaseInvoiceDetail
        {
            get { return _PurchaseInvoiceDetail; }
            private set
            {
                if (PurchaseInvoiceDetail == value) return;
                _PurchaseInvoiceDetail = value;
                FirePropertyChanged("PurchaseInvoiceDetail");
            }
        }

        public ICommand GetInventoryCommand { get; set; }
        public ICommand GetQtyUnitCommand { get; set; }
        public ICommand GetTotalDetailCommand { get; set; }
        public ICommand GetPpnCommand { get; set; }
        public ICommand GetTotalDiscountCommand { get; set; }

        public bool CanEditCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteCommand(Object param)
        {
            return true;
        }

        public bool CanAddDetailCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteDetailCommand(Object param)
        {
            return true;
        }


        public void Edit(Object param)
        {
            PurchaseInvoiceViewModel.mode = Mode.Edit;
            Navigation.MyNavigation.Navigate(new Uri("/PurchaseInvoice/frmAdd", UriKind.Relative));
            Navigation.Args = param;
        }

        public void Delete(Object param)
        {     
            DeleteConfirmation deleteConfirmation = new DeleteConfirmation();
            deleteConfirmation.Show();
            EventAggregator.RegisterMessage("ApprovalSucceeded", (x) =>
            {
                deleteConfirmation.Close();
                client.DeleteCompleted += client_DeleteCompleted;
                client.DeleteAsync((PurchaseInvoiceDTO)param);
            });

        }

        private void client_DeleteCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.DeleteCompleted -= client_DeleteCompleted;
            MessageBox.Show("Delete Success!");
            PurchaseInvoiceViewModel.mode = Mode.Idle;
            var VM = new PurchaseInvoiceViewModel();
        }


        public void GetInventoryList()
        {
            Inventoryclient.GetInventoryByCriteriaCompleted +=
                InventoryClient_GetListByCriteriaCompleted;
            Inventoryclient.GetInventoryByCriteriaAsync(new Dictionary<string, object>(), null, 1);
        }

        private void InventoryClient_GetListByCriteriaCompleted(object sender,
                                                                GetInventoryByCriteriaCompletedEventArgs e)
        {
            Inventorys = e.Result;
            if (PurchaseInvoiceViewModel.PurchaseInvoice != null)
            {
                foreach (
                    PurchaseInvoiceDetailDTO PurchaseInvoiceDetail in
                        PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails)
                {
                    if (PurchaseInvoiceDetail.Inventory == null) continue;
                    PurchaseInvoiceDetail.Inventory =
                        Inventorys.FirstOrDefault(s => s.SerialNumber == PurchaseInvoiceDetail.Inventory.SerialNumber);
                }
            }
        }


        public void GetInventory(Object param)
        {
            PurchaseInvoiceDetail = (PurchaseInvoiceDetailDTO) param;
            if (PurchaseInvoiceDetail.Inventory.QtyUnit != 0) return;
            string SerialNumber = PurchaseInvoiceDetail.Inventory.SerialNumber;
            Inventoryclient.GetInventoryCompleted +=
                InventoryClient_GetInventoryCompleted;
            Inventoryclient.GetInventoryAsync(SerialNumber);
        }

        private void InventoryClient_GetInventoryCompleted(object sender, GetInventoryCompletedEventArgs e)
        {
            Inventoryclient.GetInventoryCompleted -=
                InventoryClient_GetInventoryCompleted;
            InventoryDTO InventoryTemp = e.Result;
            if (null != InventoryTemp  && ! string.IsNullOrEmpty(InventoryTemp.SerialNumber))
            {
                PurchaseInvoiceDetail.Inventory = InventoryTemp;
                PurchaseInvoiceDetail.Inventory.Item =
                    e.Result.Item;
                PurchaseInvoiceDetail.Inventory.SatuanUnit =
                    e.Result.SatuanUnit;
            }else
            {
               MessageBox.Show("Barang tidak ditemukan, coba entry secara manual");
               return;
               
            }
        }

        public void AddPurchaseInvoiceDetail(Object param)
        {
            PurchaseInvoiceDetail = new PurchaseInvoiceDetailDTO();
            PurchaseInvoiceDetail.Inventory = new InventoryDTO();
            PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.Add(PurchaseInvoiceDetail);
        }

        public void DeletePurchaseInvoiceDetail(Object param)
        {
            var PurchaseInvoiceDetail = (PurchaseInvoiceDetailDTO) param;
            if (PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.Count > 1)
            {
                if (param == null)
                {
                    int count = PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.Count;
                    PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.RemoveAt(count-1);
                }else
                {
                    PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.Remove(PurchaseInvoiceDetail);
                }
                
                GetTotalDetail(PurchaseInvoiceDetail);
                  
            }
        }

     


        public bool CanGetInventoryCommand(Object param)
        {
            return true;
        }

        public bool CanGetQtyUnit(Object param)
        {
            return true;
        }

        public void GetQtyUnit(Object param)
        {
            PurchaseInvoiceDetail = (PurchaseInvoiceDetailDTO) param;
            if (PurchaseInvoiceDetail.Inventory != null)
            {
                PurchaseInvoiceDetail.Inventory.QtyUnit = PurchaseInvoiceDetail.Inventory.QtyPack *
                                                         (PurchaseInvoiceDetail.Inventory.Panjang *
                                                          PurchaseInvoiceDetail.Inventory.Lebar *
                                                          PurchaseInvoiceDetail.Inventory.Tinggi) /
                                                         PurchaseInvoiceDetail.Inventory.SatuanUnit.Pengali;

                PurchaseInvoiceDetail.Inventory.QtyUnit = PurchaseInvoiceDetail.Inventory.Item.IsRounded
                                            ? PurchaseInvoiceDetail.Inventory.QtyUnit.Round(2,MidpointRounding.AwayFromZero)
                                            : PurchaseInvoiceDetail.Inventory.QtyUnit.Round(4, MidpointRounding.AwayFromZero);

                PurchaseInvoiceDetail.Qty = PurchaseInvoiceDetail.Inventory.QtyUnit;

            }
               


        }


        public bool CanGetTotalDetailCommand(Object param)
        {
            return true;
        }

        public void GetTotalDetail(Object param)
        {
            PurchaseInvoiceDetail = (PurchaseInvoiceDetailDTO) param;
            if (PurchaseInvoiceViewModel.PurchaseInvoice.Kurs != 1)
                PurchaseInvoiceDetail.Price = PurchaseInvoiceDetail.Price * PurchaseInvoiceViewModel.PurchaseInvoice.Kurs;

            if (PurchaseInvoiceDetail.DiscountType != "%")
                PurchaseInvoiceDetail.TotalDetail = (PurchaseInvoiceDetail.Inventory.QtyUnit*PurchaseInvoiceDetail.Price) -
                                                    PurchaseInvoiceDetail.Discount;
            else
                PurchaseInvoiceDetail.TotalDetail = (PurchaseInvoiceDetail.Inventory.QtyUnit*PurchaseInvoiceDetail.Price) -
                                                    ((PurchaseInvoiceDetail.Price)*PurchaseInvoiceDetail.Discount/100);
            PurchaseInvoiceViewModel.PurchaseInvoice.SubTotal =
                PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.Sum(p => p.TotalDetail);
            if (PurchaseInvoiceViewModel.PurchaseInvoice.DiscountType != "%")
                PurchaseInvoiceViewModel.PurchaseInvoice.AfterDiscount =
                    PurchaseInvoiceViewModel.PurchaseInvoice.SubTotal -
                    PurchaseInvoiceViewModel.PurchaseInvoice.Discount;
            else
                PurchaseInvoiceViewModel.PurchaseInvoice.AfterDiscount =
                    PurchaseInvoiceViewModel.PurchaseInvoice.SubTotal -
                    (PurchaseInvoiceViewModel.PurchaseInvoice.SubTotal*PurchaseInvoiceViewModel.PurchaseInvoice.Discount/
                     100);
            if (PurchaseInvoiceViewModel.PurchaseInvoice.IsPpn)
                PurchaseInvoiceViewModel.PurchaseInvoice.Ppn = PurchaseInvoiceViewModel.PurchaseInvoice.AfterDiscount*10/
                                                               100;
            if (PurchaseInvoiceViewModel.PurchaseInvoice.Ppn > 0)
                PurchaseInvoiceViewModel.PurchaseInvoice.IsPpn = true;
            PurchaseInvoiceViewModel.PurchaseInvoice.Total =
                PurchaseInvoiceViewModel.PurchaseInvoice.AfterDiscount + PurchaseInvoiceViewModel.PurchaseInvoice.Ppn;

            PurchaseInvoiceViewModel.TotalQtyUnit =
                PurchaseInvoiceViewModel.PurchaseInvoice.PurchaseInvoiceDetails.Sum(x => x.Inventory.QtyUnit);
        }


        public bool CanGetPpnCommand(Object param)
        {
            return true;
        }

        public void GetPpn(Object param)
        {
            var PurchaseInvoice = (PurchaseInvoiceDTO) param;
            if (PurchaseInvoice.IsPpn)
            {
                PurchaseInvoice.Ppn = PurchaseInvoice.AfterDiscount*10/100;
                PurchaseInvoice.Total = PurchaseInvoice.AfterDiscount + PurchaseInvoice.Ppn;
            }
            else
            {
                PurchaseInvoice.Ppn = 0;
                PurchaseInvoice.Total = PurchaseInvoice.AfterDiscount + PurchaseInvoice.Ppn;
            }
        }

        public bool CanGetTotalDiscount(Object param)
        {
            return true;
        }

        public void GetTotalDiscount(Object param)
        {
            var PurchaseInvoice = (PurchaseInvoiceDTO) param;
            if (PurchaseInvoice.PurchaseInvoiceDetails != null)
                PurchaseInvoice.SubTotal =
                    PurchaseInvoice.PurchaseInvoiceDetails.Sum(p => p.TotalDetail);
            if (PurchaseInvoice.DiscountType != "%")
                PurchaseInvoice.AfterDiscount = PurchaseInvoice.SubTotal - PurchaseInvoice.Discount;
            else
                PurchaseInvoice.AfterDiscount = PurchaseInvoice.SubTotal -
                                                (PurchaseInvoice.SubTotal*PurchaseInvoice.Discount/100);
            if (PurchaseInvoice.IsPpn)
                PurchaseInvoice.Ppn = PurchaseInvoice.AfterDiscount*10/100;
            if (PurchaseInvoice.Ppn > 0)
                PurchaseInvoice.IsPpn = true;
            PurchaseInvoice.Total =
                PurchaseInvoice.AfterDiscount + PurchaseInvoice.Ppn;
        }
    }


    public class PurchaseInvoiceConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null)
            {
                return ((dynamic) value).PINo;
            }
            else
            {
                return string.Empty;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}